﻿#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>//输入输出流

using namespace std;//std是标准库
//int main()
//{
//	cout << "hello world\n" << endl;//<<是插入到控制台(可以自动识别类型)
//	return 0;
//}

//namespace的价值
//#include <stdio.h>//使用C语言时rand是一个函数,当再定义一个rand变量时会冲突
//#include <stdlib.h>
//int rand = 10;
//int main()
//{
//	// 编译报错：error C2365: “rand”: 重定义；以前的定义是“函数”
//	printf("%d\n", rand);
//	return 0;
//}

//namespace关键字的使用
#include <stdio.h>
#include <stdlib.h>
// 1. 正常的命名空间定义
//namespace pj
//{
//	// 命名空间中可以定义变量/函数/类型
//	int rand = 10;
//	int Add(int left, int right)
//	{
//		return left + right;
//	}
//	struct Node
//	{
//		struct Node* next;
//		int val;
//	};
//}
//int main()
//{
//	// 这⾥默认是访问的是全局的rand函数指针
//	printf("%p\n", rand);
//	// 这⾥指定bit命名空间中的rand
//	printf("%d\n", pj::rand);
//	return 0;
//}
//2. 命名空间可以嵌套
//namespace fpj
//{
//	namespace f1//namespace本质是定义⼀个域，这个域跟全局域各⾃独⽴，不同的域可以定义同名变量，例如f1和f2
//	{
//		int Add(int left, int right)
//		{
//			return left + right;
//		}
//	}
//	namespace f2
//	{
//		int Add(int left, int right)
//		{
//			return left + right;
//		}
//	}
//}
//int main()
//{
//	printf("%d\n", fpj::f1::Add(1, 2));
//	printf("%d\n", fpj::f2::Add(1, 2));
//	return 0;
//}

//#include"stack.h"//// 多⽂件中可以定义同名namespace，会默认合并到⼀起，就像同⼀个namespace⼀样.例如stack.h和stack.cpp同时使用namespace fpj;
//typedef struct Stack
//{
//	int a[10];
//	int top;
//}ST;
//int main()
//{
//	// 调用fpj namespace的
//	fpj::ST st2;
//	printf("%d\n", sizeof(st2));
//	fpj::STInit(&st2, 4);
//	fpj::STPush(&st2, 1);
//	fpj::STPush(&st2, 2);
//
//	return 0;
//}

//命名空间的使用
//namespace pj
//{
//	int a = 0;
//	int b = 1;
//}
//using namespace pj;//展开整个命名空间
//using pj::a;//using将命名空间中某个成员展开
//int main()
//{
//	printf("%d\n", a);
//	printf("%d\n", a);
//	printf("%d\n", a);
//	printf("%d\n", a);
//	printf("%d\n", a);
//	printf("%d\n", a);
//	printf("%d\n", pj::b);//单独指定b,因为b用的次数少
//	return 0;
//}

//输入和输出
//std::cin 是 istream 类的对象，它主要⾯向窄字符（narrow characters(of type char)）的标准输⼊流。
//std::cout 是 ostream 类的对象，它主要⾯向窄字符的标准输出流。
//std::endl 是⼀个函数，流插⼊输出时，相当于插⼊⼀个换⾏字符加刷新缓冲区.
//<<是流插⼊运算符(输出)，>>是流提取运算符
//using namespace std;
//int main()
//{
//	int i = 1234;
//	int j = -1234;
//	//std::cout << i << endl;
//	cout << i << endl;
//
//	int a = 0;
//	double b = 0.1;
//	char c = 'x';
//
//	cout << a << "             " << b << " " << c << "\n" << '\n' << endl;//输出多个
//	std::cout << a << " " << b << " " << c << std::endl;
//
//	scanf("%d%lf", &a, &b);
//	printf("%d %lf\n", a, b);
//
//	// 可以自动识别变量的类型
//	//cin >> a;
//	//cin >> b >> c;
//	cin >>a>> b >> c;
//	cout << a << endl;
//	cout << b << " " << c << endl;
//
//	return 0;
//}
//int main()
//{
//	double d = 2.22222222;
//	printf("%.2lf\n", d);
//	cout << d << endl;
//	cout << &d << endl;
//	return 0;
//}

//缺省参数
//#include <iostream>
//#include <assert.h>
//using namespace std;
//void Func(int a = 0)//缺省参数相当于默认值
//{
//	cout << a << endl;
//}
//int main()
//{
//	Func(); // 没有传参时，使⽤参数的默认值0
//	Func(10); // 传参时，使⽤指定的实参10
//	return 0;
//}
//#include <iostream>
//using namespace std;
//// 全缺省
//void Func1(int a = 10, int b = 20, int c = 30)
//{
//	cout << "a = " << a << endl;
//	cout << "b = " << b << endl;
//	cout << "c = " << c << endl << endl;
//}
//// 半缺省
//void Func2(int a, int b = 10, int c = 20)//半缺省参数必须从右往左依次连续缺省，不能间隔跳跃给缺省值。
//{
//	cout << "a = " << a << endl;
//	cout << "b = " << b << endl;
//	cout << "c = " << c << endl << endl;
//}
//int main()
//{
//	Func1();
//	Func1(1);
//	Func1(1, 2);
//	Func1(1, 2, 3);
//	Func2(100);//带缺省参数的函数调⽤，C++规定必须从左到右依次给实参，不能跳跃给实参
//	Func2(100, 200);
//	Func2(100, 200, 300);
//	return 0;
//}

//函数重载(C++⽀持在同⼀作⽤域中出现同名函数，但是要求这些同名函数的形参不同，可以是参数个数不同或者类型不同。)
// 1、参数类型不同
//int Add(int left, int right)
//{
//	cout << "int Add(int left, int right)" << endl;
//	return left + right;
//}
//double Add(double left, double right)
//{
//	cout << "double Add(double left, double right)" << endl;
//	return left + right;
//}
// 2、参数个数不同
//void f()
//{
//	cout << "f()" << endl;
//}
//void f(int a)
//{
//	cout << "f(int a)" << endl;
//}
// 3、参数类型顺序不同
//void f(int a, char b)
//{
//	cout << "f(int a,char b)" << endl;
//}
//void f(char b, int a)
//{
//	cout << "f(char b, int a)" << endl;
//}

// 返回值不同不能作为重载条件，因为调⽤时也⽆法区分
//void fxx()
//{
// 
// }
//int fxx()
//{
// return 0;
//}

//引用(是给已存在变量取了⼀个别名)  类型& 引⽤别名 = 引⽤对象;
int main()
{
	int a = 0;
	// 引⽤：b和c是a的别名
	int& b = a;
	int& c = a;
	// 也可以给别名b取别名，d相当于还是a的别名
	int& d = b;
	++d;
	// 这⾥取地址我们看到是⼀样的
	cout << &a << endl;
	cout << &b << endl;
	cout << &c << endl;
	cout << &d << endl;
	return 0;
}
int main()
{
	int a = 10;
	         // 编译报错：“ra”: 必须初始化引⽤,引⽤在定义时必须初始化
	        //int& ra;
	int& b = a;
	int c = 20;

	// 下面并⾮让b引⽤c，因为C++引⽤不能改变指向，
	b = c;// 这⾥是⼀个赋值
	cout << &a << endl;
	cout << &b << endl;
	cout << &c << endl;
	return 0;
}

//引用的使用(和指针传参是类似的)
void Swap(int& rx, int& ry)
{
	int tmp = rx;
	rx = ry;
	ry = tmp;
}
void Swap(int* px, int* py)
{

}

//const引用  对象的访问权限在引⽤过程中可以缩⼩，但是不能放⼤

//int& rb = a * 3; 
// double d = 12.34; int& rd = d; 
// 这样⼀些场景下a * 3的和结果保存在⼀个临时对象中， int& rd = d 也是类似，在类型转换中会产⽣临时对
//象存储中间值，也就是时，rb和rd引⽤的都是临时对象，⽽C++规定临时对象具有常性，所以这⾥就触发了权限放⼤，必须要⽤常引⽤才可以。
//临时对象具有常性,所以需要const;
int main()
{
	int a = 10;
	const int& ra = 30;

	// 编译报错: “初始化”: ⽆法从“int”转换为“int &”
	// int& rb = a * 3;
	const int& rb = a * 3;//ok


	double d = 12.34;
	// 编译报错：“初始化”: ⽆法从“double”转换为“int &”
	// int& rd = d;
	const int& rd = d;//ok
	return 0;
}


int main()
{
	const int a = 10;
	// 编译报错：error C2440: “初始化”: ⽆法从“const int”转换为“int &”这⾥的引⽤是对a访问权限的放⼤
	//int& ra = a;
	const int& ra = a;// 这样才可以

	// 编译报错：error C3892: “ra”: 不能给常量赋值
	//ra++;

	int b = 20;// 这⾥的引⽤是对b访问权限的缩⼩
	const int& rb = b;
	// 编译报错：error C3892: “rb”: 不能给常量赋值
	//rb++;

	return 0;
}

